/**
* @Author: Zhengfeng.Yao
* @Date:   2017-01-23 14:12:23
* @Last modified by:   Zhengfeng.Yao
* @Last modified time: 2017-02-09 14:49:52
*/

import React, { Component } from 'react';
import cn from 'classnames';
import { Tree, Button, Checkbox } from 'antd';
import './treeTransfer.less';
import _ from 'lodash';

const prefix = 'aegis-treeTransfer';
const TreeNode = Tree.TreeNode;

export default class TreeTransfer extends Component {
  constructor(props) {
    super(props);
    const { sourceData, targetData, leftExpandedKeys, rightExpandedKeys, leftCheckedKeys, rightCheckedKeys } = props;
    this.state = {
      sourceDataAllChecked: false,
      targetDataAllChecked: false,
      sourceData: sourceData || [],
      targetData: targetData || [],
      leftExpandedKeys: leftExpandedKeys || [],
      rightExpandedKeys: rightExpandedKeys || [],
      leftCheckedKeys: leftCheckedKeys || [],
      rightCheckedKeys: rightCheckedKeys || []
    };
  }

  componentWillReceiveProps(props) {
    const sourceData = props.sourceData || [];
    const targetData = props.targetData || [];
    const leftExpandedKeys = this.state.leftExpandedKeys.slice(0);
    const rightExpandedKeys = this.state.rightExpandedKeys.slice(0);
    const leftCheckedKeys = this.state.leftCheckedKeys.slice(0);
    const rightCheckedKeys = this.state.rightCheckedKeys.slice(0);
    const leftRemoveExpandedKeys = [];
    const rightRemoveExpandedKeys = [];
    const leftRemoveCheckedKeys = [];
    const rightRemoveCheckedKeys = [];

    leftExpandedKeys.forEach(key => {
      if (!sourceData.find(item => item.key == key)) {
        leftRemoveExpandedKeys.push(key);
      }
    });
    rightExpandedKeys.forEach(key => {
      if (!targetData.find(item => item.key == key)) {
        rightRemoveExpandedKeys.push(key);
      }
    });

    leftCheckedKeys.forEach(key => {
      const newItem = sourceData.find(item => item.key == key || item.children.find(leaf => leaf.key == key));
      if (!newItem) {
        leftRemoveCheckedKeys.push(key);
      } else {
        if (newItem.key == key && !_.includes(leftCheckedKeys, ...newItem.children.map(leaf => leaf.key))) {
          leftRemoveCheckedKeys.push(key);
        }
      }
    });
    rightCheckedKeys.forEach(key => {
      const newItem = targetData.find(item => item.key == key || item.children.find(leaf => leaf.key == key));
      if (!newItem) {
        rightRemoveCheckedKeys.push(key);
      } else {
        if (newItem.key == key && !_.includes(rightCheckedKeys, ...newItem.children.map(leaf => leaf.key))) {
          rightRemoveCheckedKeys.push(key);
        }
      }
    });

    const newRightCheckedKeys = _.without(rightCheckedKeys, ...rightRemoveCheckedKeys);
    const newLeftCheckedKeys = _.without(leftCheckedKeys, ...leftRemoveCheckedKeys);
    const allRightKeys = _(targetData).map(item => item.children.filter(leaf => !leaf.disabled).map(leaf => leaf.key)).reduce((result, value) => result.concat(value), []);
    const allLeftKeys = _(sourceData).map(item => item.children.map(leaf => leaf.key)).reduce((result, value) => result.concat(value), []);
    const sourceDataAllChecked = !allLeftKeys.length ? false : !_.without(allLeftKeys, ...newLeftCheckedKeys).length;
    const targetDataAllChecked = !allRightKeys.length ? false : !_.without(allRightKeys, ...newRightCheckedKeys).length;

    this.setState({
      sourceData: sourceData,
      targetData: targetData,
      sourceDataAllChecked: sourceDataAllChecked,
      targetDataAllChecked: targetDataAllChecked,
      leftExpandedKeys: _.without(leftExpandedKeys, ...leftRemoveExpandedKeys),
      rightExpandedKeys: _.without(rightExpandedKeys, ...rightRemoveExpandedKeys),
      leftCheckedKeys: newLeftCheckedKeys,
      rightCheckedKeys: newRightCheckedKeys
    });
  }

  onExpand = key => expandedKeys => {
    this.setState({[key]: expandedKeys});
  };

  onCheck = (key, dataKey) => checkedKeys => {
    const data = this.state[dataKey];
    const allKeys = _(data).map(item => item.children.filter(leaf => !leaf.disabled).map(leaf => leaf.key)).reduce((result, value) => result.concat(value), []);
    const allChecked = !allKeys.length ? false : !_.without(allKeys, ...checkedKeys).length;
    this.setState({[key]: checkedKeys, [`${dataKey}AllChecked`]: allChecked});
  };

  onSelectAll = (key, data) => e => {
    const checkedKeys = [];
    if (e.target.checked) {
      this.state[data].filter(item => item.children.find(leaf => !leaf.disabled)).forEach(item => {
        item.children.filter(leaf => !leaf.disabled).forEach(leaf => checkedKeys.push(leaf.key));
        checkedKeys.push(item.key);
      });
    }
    this.setState({[key]: checkedKeys, [`${data}AllChecked`]: e.target.checked});
  };

  onMoveLeft = () => {
    const { leftExpandedKeys, rightExpandedKeys, leftCheckedKeys, rightCheckedKeys, targetData } = this.state;
    const expandedKeys = rightExpandedKeys.filter(key => targetData.find(item => item.key == key && item.children.find(leaf => !leaf.disabled)));
    const checkedKeys = rightCheckedKeys.filter(key => targetData.find(item => item.children.find(leaf => leaf.key == key && !leaf.disabled)));
    const newLeftExpandedKeys = _.uniq(leftExpandedKeys.concat(expandedKeys.filter(key => !!checkedKeys.find(item => item == key))));
    const newLeftCheckedKeys = _.uniq(leftCheckedKeys.concat(checkedKeys));
    const newRightExpandedKeys = expandedKeys.filter(key => !checkedKeys.find(item => item == key));
    const moveKeys = checkedKeys.slice(0);

    this.setState({
      leftCheckedKeys: newLeftCheckedKeys,
      leftExpandedKeys: newLeftExpandedKeys,
      rightExpandedKeys: newRightExpandedKeys,
      rightCheckedKeys: []
    });
    const self = this;

    setTimeout(() => {
      if (self.props.onMoveLeft) {
        self.props.onMoveLeft(moveKeys);
      }
    });
  };

  onMoveRight = () => {
    const { leftExpandedKeys, rightExpandedKeys, leftCheckedKeys, rightCheckedKeys } = this.state;
    const newRightExpandedKeys = _.uniq(rightExpandedKeys.concat(leftExpandedKeys.filter(key => !!leftCheckedKeys.find(item => item == key))));
    const newRightCheckedKeys = _.uniq(rightCheckedKeys.concat(leftCheckedKeys));
    const newLeftExpandedKeys = leftExpandedKeys.filter(key => !leftCheckedKeys.find(item => item == key));
    const moveKeys = leftCheckedKeys.slice(0);

    this.setState({
      rightCheckedKeys: newRightCheckedKeys,
      rightExpandedKeys: newRightExpandedKeys,
      leftExpandedKeys: newLeftExpandedKeys,
      leftCheckedKeys: []
    });
    const self = this;

    setTimeout(() => {
      if (self.props.onMoveRight) {
        self.props.onMoveRight(moveKeys);
      }
    });
  };

  render() {
    const { titles } = this.props;
    const { sourceData, targetData, sourceDataAllChecked, targetDataAllChecked, leftExpandedKeys, rightExpandedKeys, leftCheckedKeys, rightCheckedKeys } = this.state;
    return (
      <div className={prefix}>
        <div className={`${prefix}-list`}>
          <div className={`${prefix}-list-header`}>
            <Checkbox onChange={this.onSelectAll('leftCheckedKeys', 'sourceData')} checked={sourceDataAllChecked}/>
            <span className={`${prefix}-list-header-selected`}>
              <span>全选</span>
              {
                titles && titles[0] && <span className={`${prefix}-list-header-title`}>{titles[0]}</span>
              }
            </span>
          </div>
          <div className={`${prefix}-list-body`}>
            {
              sourceData.length ? <Tree
                checkable
                expandedKeys={leftExpandedKeys}
                checkedKeys={leftCheckedKeys}
                autoExpandParent={false}
                onExpand={this.onExpand('leftExpandedKeys')}
                onCheck={this.onCheck('leftCheckedKeys', 'sourceData')}
                >
                  {
                    sourceData.map(item => {
                      if (item.children && item.children.length) {
                        return <TreeNode key={item.key} title={item.title}>
                          {
                            item.children.map(leaf => <TreeNode key={leaf.key} title={leaf.title} />)
                          }
                        </TreeNode>
                      }
                    })
                  }
                </Tree> : ''
            }
            <div className={`${prefix}-list-body-not-found`} style={{display: sourceData.length ? 'none' : 'block'}}>暂无数据</div>
          </div>
        </div>
        <div className={`${prefix}-operation`}>
          <Button type="primary" size="default" icon="left"
            disabled={!rightCheckedKeys.length}
            onClick={this.onMoveLeft}
            ></Button>
          <Button type="primary" size="default" icon="right"
            disabled={!leftCheckedKeys.length}
            onClick={this.onMoveRight}
            ></Button>
        </div>
        <div className={`${prefix}-list`}>
          <div className={`${prefix}-list-header`}>
            <Checkbox onChange={this.onSelectAll('rightCheckedKeys', 'targetData')}
              disabled={!targetData.find(item => item.children.find(leaf => !leaf.disabled))}
              checked={targetDataAllChecked}
              />
            <span className={`${prefix}-list-header-selected`}>
              <span>全选</span>
              {
                titles && titles[1] && <span className={`${prefix}-list-header-title`}>{titles[1]}</span>
              }
            </span>
          </div>
          <div className={`${prefix}-list-body`}>
            {
              targetData.length ? <Tree
                checkable
                expandedKeys={rightExpandedKeys}
                checkedKeys={rightCheckedKeys}
                autoExpandParent={false}
                onExpand={this.onExpand('rightExpandedKeys')}
                onCheck={this.onCheck('rightCheckedKeys', 'targetData')}
                >
                  {
                    targetData.map(item => {
                      if (item.children && item.children.length) {
                        return <TreeNode key={item.key} title={item.title} selectable={item.children.find(leaf => !leaf.disabled)} disableCheckbox={!item.children.find(leaf => !leaf.disabled)}>
                          {
                            item.children.map(leaf => <TreeNode key={leaf.key} selectable={!leaf.disabled} title={leaf.title} disableCheckbox={!!leaf.disabled}/>)
                          }
                        </TreeNode>
                      }
                    })
                  }
                </Tree> : ''
            }
            <div className={`${prefix}-list-body-not-found`} style={{display: targetData.length ? 'none' : 'block'}}>暂无数据</div>
          </div>
        </div>
      </div>
    );
  }
}
